package com.shigu.weixin.service;

import com.alibaba.fastjson.JSONObject;
import com.github.wxpay.extend.MyWxPayConfig;
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayConfig;
import com.github.wxpay.sdk.WXPayConstants;
import com.github.wxpay.sdk.WXPayUtil;

import com.shigu.util.MoneyUtil;
import com.shigu.weixin.enums.WxConfigSource;
import com.shigu.weixin.exceptions.UtilsException;
import com.shigu.weixin.util.AppPayConfig;
import com.shigu.weixin.util.HostUtil;
import com.shigu.weixin.util.XcxPayConfig;
import com.shigu.weixin.vo.AppPayVo;
import com.shigu.weixin.vo.JSAPIVo;
import com.shigu.weixin.vo.WxRefundVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 微信支付
 *
 * @author 郭尔
 * @description
 * @date 2019/1/15 12:37
 */
@Service
public class WxPayService {
    private static final Logger logger = LoggerFactory.getLogger(WxPayService.class);

    @Value("${programTest}")
    private boolean programTest;

    /**
     * JSAPI调起支付
     * 需要在微信返回prepay_id 后 将前端需要的参数重新生成 paySign签名
     *
     * @param openiid 用户的openiid
     * @return 微信返回的签名，随机串，预交易订单号
     * @author 郭尔
     * @date 2018/12/24 9:25
     */
    public JSAPIVo JSAPIPay(String outTradeNo, Double totalFee, String ip, String openiid, WxConfigSource source) throws Exception {
        JSAPIVo vo = new JSAPIVo();
        Long timeStamp = (new Date().getTime()) / 1000;//时间戳 秒级
        WXPayConfig config = null;
//        XcxPayConfig config = new XcxPayConfig();
        switch (source) {
            case GZH:
                config = new MyWxPayConfig();
                break;
            case XCX:
                config = new XcxPayConfig();
                break;
        }

        WXPay wxpay = new WXPay(config, WXPayConstants.SignType.MD5, false);

        Double d = MoneyUtil.multipy(totalFee,100D);

        Map<String, String> data = new HashMap<String, String>();
        data.put("body", "惠优品购买商品");
        data.put("notify_url", "https://" + HostUtil.selHost() + "/adminjson/payCallBack.htm");
        data.put("out_trade_no", outTradeNo);
        data.put("spbill_create_ip", ip);
        data.put("total_fee", d.longValue() + "");
        data.put("openid", openiid);
        data.put("trade_type", "JSAPI");
        Map<String, String> resp = wxpay.unifiedOrder(data);

        JSONObject obj = JSONObject.parseObject(JSONObject.toJSONString(resp));
        if (!obj.getString("return_code").equals("SUCCESS")) {
            throw new UtilsException(obj.getString("return_msg"));
        }
        if (!obj.getString("result_code").equals("SUCCESS")) {
            throw new UtilsException(obj.getString("err_code_des"));
        }
        String nonceStr = WXPayUtil.generateNonceStr();
        //需要重新生成签名
        Map<String, String> jsResp = new HashMap<String, String>();
        jsResp.put("appId", config.getAppID());//appId 使用 驼峰
        jsResp.put("timeStamp", timeStamp.toString());
        jsResp.put("nonceStr", nonceStr);
        jsResp.put("package", "prepay_id=" + obj.getString("prepay_id"));
        jsResp.put("signType", "MD5");//signType 也作为参数

        vo.setAppId(config.getAppID());
        vo.setNonceStr(nonceStr);//随机串
        vo.setPrepayId(obj.getString("prepay_id"));//预订单id
        vo.setTimeStamp(timeStamp.toString());
        vo.setPaySign(WXPayUtil.generateSignature(jsResp, config.getKey()));
        return vo;
    }

    /**
     * @description 微信移动支付
     * @
     * @author 郭尔
     * @date 2019/2/15 12:36
     */
    public AppPayVo appPay(String outTradeNo, Double totalFee, String ip) throws Exception {
        AppPayVo vo = new AppPayVo();
        Long timeStamp = new Date().getTime() / 1000L;//时间戳 秒级
        AppPayConfig config = new AppPayConfig();
        WXPay wxpay = new WXPay(config, WXPayConstants.SignType.MD5, false);

        Double d = MoneyUtil.multipy(totalFee,100D);

        Map<String, String> data = new HashMap<String, String>();
        data.put("body", "惠优品购买商品");
        data.put("notify_url", "https://" + HostUtil.selHost() + "/adminjson/payCallBack.htm");
        data.put("out_trade_no", outTradeNo);
        data.put("spbill_create_ip", ip);
        data.put("total_fee", d.longValue() + "");
        data.put("trade_type", "APP");
        Map<String, String> resp = wxpay.unifiedOrder(data);
        JSONObject obj = JSONObject.parseObject(JSONObject.toJSONString(resp));
        if (!obj.getString("return_code").equals("SUCCESS")) {
            throw new UtilsException(obj.getString("return_msg"));
        }
        if (!obj.getString("result_code").equals("SUCCESS")) {
            throw new UtilsException(obj.getString("err_code_des"));
        }
        String nonceStr = WXPayUtil.generateNonceStr();
        //需要重新生成签名
        Map<String, String> againSign = new HashMap<String, String>();
        againSign.put("appid", config.getAppID());
        againSign.put("partnerid", config.getMchID());
        againSign.put("timestamp", timeStamp.toString());
        againSign.put("noncestr", nonceStr);
        againSign.put("package", "Sign=WXPay");
        againSign.put("prepayid", obj.getString("prepay_id"));

        vo.setPartnerId(config.getMchID());
        vo.setAppId(config.getAppID());
        vo.setNonceStr(nonceStr);//随机串
        vo.setPrepayId(obj.getString("prepay_id"));//预订单id
        vo.setTimeStamp(timeStamp.toString());
        vo.setSign(WXPayUtil.generateSignature(againSign, config.getKey(), WXPayConstants.SignType.MD5));


        return vo;
    }


    /**
     * @description 微信打款
     * @author 郭尔
     * @date 2019-05-05 15:25
     */
    public void cashBack(String openiid, String tradeNo, Double money, String remark, String clientIp) throws Exception {
        if (programTest) {
            System.out.println("打款成功");
            return;
        }
        Double d = money * 100;
        AppPayConfig config = new AppPayConfig();
        WXPay wxpay = new WXPay(config, WXPayConstants.SignType.MD5, false);

        Map<String, String> data = new HashMap<String, String>();
        data.put("partner_trade_no", tradeNo);
        data.put("openid", openiid);
        data.put("check_name", "NO_CHECK");
        data.put("amount", d.longValue() + "");
        data.put("desc", remark);
        data.put("spbill_create_ip", clientIp);

        Map<String, String> resp = wxpay.mmpaymkttransfers(data);
        JSONObject obj = JSONObject.parseObject(JSONObject.toJSONString(resp));
        if (!obj.getString("result_code").equals("SUCCESS")) {
            logger.error(obj.toJSONString());
            throw new UtilsException(obj.getString("return_msg"));
        }
    }

    /**
     * @description 购买VIP 的微信支付
     * @
     * @author 郭尔
     * @date 2019/2/15 12:36
     */
    public AppPayVo vipPurchase(String outTradeNo, Double totalFee, String ip) throws Exception {
        AppPayVo vo = new AppPayVo();
        Long timeStamp = new Date().getTime() / 1000L;//时间戳 秒级
        AppPayConfig config = new AppPayConfig();
        WXPay wxpay = new WXPay(config, WXPayConstants.SignType.MD5, false);

        Double d = totalFee * 100;

        Map<String, String> data = new HashMap<String, String>();
        data.put("body", "惠优品VIP");
        data.put("notify_url", "https://" + HostUtil.selHost() + "/adminjson/vipPayCallBack.htm");
        data.put("out_trade_no", outTradeNo);
        data.put("spbill_create_ip", ip);
        data.put("total_fee", d.longValue() + "");
        data.put("trade_type", "APP");
        Map<String, String> resp = wxpay.unifiedOrder(data);
        JSONObject obj = JSONObject.parseObject(JSONObject.toJSONString(resp));
        if (!obj.getString("return_code").equals("SUCCESS")) {
            throw new UtilsException(obj.getString("return_msg"));
        }
        if (!obj.getString("result_code").equals("SUCCESS")) {
            throw new UtilsException(obj.getString("err_code_des"));
        }
        String nonceStr = WXPayUtil.generateNonceStr();
        //需要重新生成签名
        Map<String, String> againSign = new HashMap<String, String>();
        againSign.put("appid", config.getAppID());
        againSign.put("partnerid", config.getMchID());
        againSign.put("timestamp", timeStamp.toString());
        againSign.put("noncestr", nonceStr);
        againSign.put("package", "Sign=WXPay");
        againSign.put("prepayid", obj.getString("prepay_id"));

        vo.setPartnerId(config.getMchID());
        vo.setAppId(config.getAppID());
        vo.setNonceStr(nonceStr);//随机串
        vo.setPrepayId(obj.getString("prepay_id"));//预订单id
        vo.setTimeStamp(timeStamp.toString());
        vo.setSign(WXPayUtil.generateSignature(againSign, config.getKey(), WXPayConstants.SignType.MD5));

        return vo;
    }


    /**
    *  微信退款
    * @param
    * @Author 过儿
    * @Date 2019/12/18
    */
    public WxRefundVo  refund(String outRefundNo,Double totalFee,String wxNo,int source) throws Exception {

        Double d = totalFee * 100;
        WXPayConfig config = null;
        if(source == WxConfigSource.APP.getValue()){
            config = new AppPayConfig();
        }else if(source == WxConfigSource.GZH.getValue()){
            config = new MyWxPayConfig();
        }

        WXPay wxpay = new WXPay(config, WXPayConstants.SignType.HMACSHA256, false);

        Map<String, String> data = new HashMap<String, String>();
        data.put("transaction_id",wxNo);
        data.put("out_refund_no",outRefundNo);
        data.put("refund_fee",d.longValue()+"");
        data.put("total_fee",d.longValue()+"");
        data.put("refund_desc","商品订单退款");

//        logger.error(JSON.toJSONString(data));
        Map<String, String> response = wxpay.refund(data);
        WxRefundVo vo = new WxRefundVo();

        if (response.get("return_code").equals("SUCCESS")) {
            if(response.get("result_code").equals("SUCCESS")){
                vo.setOutRefundNo(response.get("out_refund_no"));
                vo.setOutTradeNo(response.get("out_trade_no"));
                vo.setRefundId(response.get("refund_id"));
                vo.setRefundFee(response.get("refund_fee"));
            }else {
                vo.setSuccess(false);
                vo.setMsg(response.get("err_code")+":"+response.get("err_code_des"));
            }
        }else{
            vo.setSuccess(false);
            vo.setMsg(response.get("return_msg"));
        }

        return vo;
    }

    public WxRefundVo queryRefund(String outRefundNo, String wxNo,String refundId) throws Exception {
        AppPayConfig config = new AppPayConfig();
        WXPay wxpay = new WXPay(config, WXPayConstants.SignType.HMACSHA256, false);
        Map<String, String> data = new HashMap<String, String>();
        data.put("transaction_id",wxNo);
        data.put("out_refund_no",outRefundNo);
        Map<String, String> response = wxpay.refundQuery(data);

        WxRefundVo vo = new WxRefundVo();
        if (response.get("return_code").equals("SUCCESS")) {
            if(response.get("result_code").equals("SUCCESS")){
                vo.setOutRefundNo(response.get("out_refund_no"));
                vo.setOutTradeNo(response.get("out_trade_no"));
                vo.setRefundId(response.get("refund_id"));
                vo.setRefundFee(response.get("refund_fee"));
            }else {
                vo.setSuccess(false);
                vo.setMsg(response.get("err_code")+":"+response.get("err_code_des"));
            }
        }else{
            vo.setSuccess(false);
            vo.setMsg(response.get("return_msg"));
        }
        return vo;
    }
}